﻿using System;
using System.Collections.Generic;
using System.Linq;
using PS.WSSDeploy.Client;
using PS.WSSDeploy.Contract;
using PS_WSSDeploy_Package.Settings;
using PS_WSSDeploy_Package.WdCommand;

namespace PS_WSSDeploy_Package.Client
{
    public class ClientContext : IClientContext, IClientSettings
    {
        private ConfigContainer ClientConfigContainer { get; set; }
        private ICmdResult _result;
        private bool Sandboxed { get; set; }
        private Config ActiveConfig { get; set; }

        private WSSDeployClient GetClient(string serverName)
        {
            var config = ActiveConfig ?? new Config {ServerName = serverName};

            var prms = new WSSDeployClient.Params
            {
                ServerName = serverName,
                ServicePort = config.ServicePort,
                CertificateFileName = config.UseCertificate ? config.CertificateFileName : string.Empty,
                CertificateFilePassword = config.GetCertificateFilePassword(),
                IdentityDnsName = config.IdentityDnsName
            };
            return new WSSDeployClient(prms);
        }

        public ClientContext(bool sandboxed, string solutionPath, ICmdResult result)
        {
            if(string.IsNullOrEmpty(solutionPath))
                throw new ArgumentNullException("solutionPath");
            if (result == null)
                throw new ArgumentNullException("result");
            _result = result;

            ClientConfigContainer = ConfigContainer.Create(solutionPath);
            Sandboxed = sandboxed;
            ActiveConfig = ClientConfigContainer.GetActiveConfig(Sandboxed);
        }

        private void ClientOp(Action<WSSDeployClient> action)
        {
            var activeServerName = ActiveConfig.ServerName;
            var servers = new List<string>(activeServerName.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries));
            foreach (var client in servers.Select(GetClient))
            {
                action(client);
            }
        }

        private void ClientSimpleServerOp(Action<WSSDeployClient> action)
        {
            var activeServerName = ActiveConfig.ServerName;
            var servers = new List<string>(activeServerName.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries));
            if(servers.Count > 0)
            {
                var client = GetClient(servers[0]);
                action(client);
            }
        }

        public void Create(string fileName)
        {
            string sandboxSiteUrl = GetSandboxSiteUrl();
            ClientSimpleServerOp(c => c.Create(sandboxSiteUrl, fileName));
        }

        public void Deploy(string fileName, string projectTargetFolder)
        {
            ClientSimpleServerOp(c =>
                {
                    var sandboxSiteUrl = GetSandboxSiteUrl();
                    var exists = c.IsExists(sandboxSiteUrl, fileName);
                    if (!exists)
                    {
                        try
                        {
                            c.Create(sandboxSiteUrl, fileName);
                            _result.WriteOutput(string.Format(WssDeployResources.CreateCmd_AddSolutionSucceeded,
                                                              fileName));
                            _result.SetSuccess();
                        }
                        catch (Exception ex)
                        {
                            _result.WriteOutput(string.Format(WssDeployResources.CreateCmd_AddSolutionError, fileName,
                                                              ex.Message));
                        }
                    }
                    var deployed = c.IsDeployed(sandboxSiteUrl, fileName);
                    DeployParams deployParams = GetDeployParams();
                    if (deployed)
                    {
                        try
                        {
                            c.Uninstall(fileName, deployParams);
                            _result.WriteOutput(string.Format(WssDeployResources.UninstallCmd_UninstallSolutionSucceeded, fileName));
                            _result.SetSuccess();
                        }
                        catch (Exception ex)
                        {
                            _result.WriteOutput(string.Format(WssDeployResources.UninstallCmd_UninstallSolutionError, fileName, ex.Message));
                            _result.SetFailed();
                        }
                        try
                        {
                            c.Create(sandboxSiteUrl, fileName);
                            _result.WriteOutput(string.Format(WssDeployResources.CreateCmd_AddSolutionSucceeded,
                                                              fileName));
                            _result.SetSuccess();
                        }
                        catch (Exception ex)
                        {
                            _result.WriteOutput(string.Format(WssDeployResources.CreateCmd_AddSolutionError, fileName,
                                                              ex.Message));
                        }
                    }
                    c.Deploy(fileName, deployParams);
                    if(Sandboxed && ActiveConfig.CopyPdbForSandbox)
                    {
                        try
                        {
                            c.CopyPdbTo(projectTargetFolder, WssDeployResources.WindowsStandartPdbFolder);
                            _result.WriteOutput(string.Format(WssDeployResources.CopyPdb_Succeeded));
                        }
                        catch (Exception ex)
                        {
                            _result.WriteOutput(string.Format(WssDeployResources.CopyPdb_Error, ex.Message));
                        }
                    }
                });
        }

        public void Uninstall(string fileName)
        {
            var deployParams = GetDeployParams();
            ClientSimpleServerOp(c => c.Uninstall(fileName, deployParams));
        }

        public void Upgrade(string fileName)
        {
            string sandboxSiteUrl = GetSandboxSiteUrl();
            ClientSimpleServerOp(c => c.Upgrade(sandboxSiteUrl, fileName));
        }

        public void CopyToRoot(string sharePointRootFolder, string path)
        {
            ClientOp(c => c.CopyToRoot(sharePointRootFolder, path));
        }

        public void CopyToRoot(List<RootFile> rootFiles)
        {
            ClientOp(c => c.CopyToRoot(rootFiles));
        }

        public int CopyToGAC(string path)
        {
            int ret = 0;
            ClientOp(c => ret = c.CopyToGAC(path));
            return ret;
        }

        public int CopyTargetToGAC(string targetPath)
        {
            int ret = 0;
            ClientOp(c => ret = c.CopyTargetToGAC(targetPath));
            return ret;
        }

        public void RecycleAppPools()
        {
            ClientOp(c => c.RecycleAppPools());
        }

        public void StartRemoteDebuggerMonitor()
        {
            ClientOp(c => c.StartRemoteDebuggerMonitor(ActiveConfig.RemoteDebuggerLogin, ActiveConfig.GetRemoteDebuggerPassword()));
        }

        public void KillRemoteDebuggerMonitor()
        {
            ClientOp(c => c.KillRemoteDebuggerMonitor());
        }

        public void CreateDebugAccount()
        {
            ClientOp(c => c.CreateDebugAccount(ActiveConfig.RemoteDebuggerLogin, ActiveConfig.GetRemoteDebuggerPassword()));
        }

        public List<string> GetFarmServerList(string serverName)
        {
            var client = GetClient(serverName);
            var serverList = client.GetFarmServerList();
            var ret = new List<string>(serverList.Split(new[] {"#;"}, StringSplitOptions.RemoveEmptyEntries));
            return ret;
        }

        public List<string> GetWebApplicationList(string serverName)
        {
            var client = GetClient(serverName);
            var webAppList = client.GetWebApplicationList();
            var list = new List<string>(webAppList.Split(new[] { "#;" }, StringSplitOptions.RemoveEmptyEntries));
            var ret = new List<string>();
            int idx = 0;
            foreach (var item in list)
            {
                if(idx % 2 == 0) ret.Add(item);
                ++idx;
            }
            return ret;
        }

        private DeployParams GetDeployParams()
        {
            DeployParams ret;
            if (Sandboxed)
            {
                ret = new DeployParams { SandboxSiteUrl = ActiveConfig.SandboxSiteUrl };
            }
            else
            {
                ret = new DeployParams
                          {
                              WspContainsResources = ActiveConfig.WspContainsResources
                          };
            }
            return ret;
        }

        private string GetSandboxSiteUrl()
        {
            return Sandboxed ? ActiveConfig.SandboxSiteUrl : string.Empty;
        }

        public ConfigContainer ConfigContainer
        {
            get { return ClientConfigContainer; }
        }
    }
}
